//
//  TokenInfo.cpp
//  LightBasic
//
//  Created by Albert on 23/03/2011.
//  Copyright 2011 LightBasic Development Team. All rights reserved.
//

#include "TokenInfo.h"
#include <boost/assign/std/map.hpp>
#include <boost/assign/list_of.hpp>
#include "StringRef.h"
using namespace lbc;

// keywords map
typedef boost::unordered_map<std::string, TokenType> KeywordMap;
static KeywordMap _keywords = boost::assign::map_list_of
    #define KEYWORD(id, ...)        (#id, TknKw##id)
    #define OPERATOR_ALIAS(id, op)  (#id, TknOp##op)
    #include "TokenInfo.def.h"
;


// token name lookup
static const StringRef namelookup[] = {
    #define TOKEN(id, str,...)      str,
    #define OPERATOR(id, str, ...)  str,
    #define KEYWORD(id, ...)        #id,
    #include "TokenInfo.def.h"
    "-invalid-token-id-"
};

/// Token flags
static enum TokenFlags {
    TknFLAG_TOKEN           = 1 << 0,
    TknFLAG_OPERATOR        = 1 << 1,
    TknFLAG_KEYWORD         = 1 << 2,
    TknFLAG_OPERATOR_RTL    = 1 << 3,
    TknFLAG_OPERATOR_UNARY  = 1 << 4,
    TknFLAG_OPERATOR_BINARY = 1 << 5
};
static unsigned int _tokenFlags[] = {
    #define RTL                                 TknFLAG_OPERATOR_RTL
    #define UNARY                               TknFLAG_OPERATOR_UNARY
    #define BINARY                              TknFLAG_OPERATOR_BINARY
    #define TOKEN(id, ...)                      TknFLAG_TOKEN,
    #define OPERATOR(id, str, lit, prec, flags) (prec << 16) | TknFLAG_OPERATOR | flags,
    #define KEYWORD(id, ...)                    TknFLAG_KEYWORD,
    #include "TokenInfo.def.h"
    #undef RTL
    #undef UNARY
};


/**
 * Find token class bu string
 */
TokenType lbc::TokenInfo::GetTokenType(const std::string & ident, TokenType def)
{
    KeywordMap::iterator iter = _keywords.find(ident);
    if (iter != _keywords.end()) return iter->second;
    return def;
}


/**
 * Get token name by type
 */
const StringRef & lbc::TokenInfo::GetTokenName(TokenType type)
{
    return namelookup[(int)type];
}


/// get operator precedence
int lbc::TokenInfo::GetOperatorPrecedence(TokenType type)
{
    assert(IsOperator(type) && "Not operator passed");
    return (_tokenFlags[(int)type]) >> 16;
}


/// is operator?
bool lbc::TokenInfo::IsOperator(TokenType type)
{
    return (_tokenFlags[(int)type] & TknFLAG_OPERATOR) != 0;
}


/// Is binary operator?
bool lbc::TokenInfo::IsBinaryOperator(TokenType type)
{
    return (_tokenFlags[(int)type] & TknFLAG_OPERATOR_BINARY) != 0;
}


/// Is unary operator?
bool lbc::TokenInfo::IsUnaryOperator(TokenType type)
{
    return (_tokenFlags[(int)type] & TknFLAG_OPERATOR_UNARY) != 0;
}

/// Is right to left associative?
bool lbc::TokenInfo::IsRtlOperator(TokenType type)
{
    return (_tokenFlags[(int)type] & TknFLAG_OPERATOR_RTL) != 0;
}


/// Is keyword token?
bool lbc::TokenInfo::IsKeyword(TokenType type)
{
    return (_tokenFlags[(int)type] & TknFLAG_KEYWORD) != 0;
}


/// Is generic token?
bool lbc::TokenInfo::IsToken(TokenType type)
{
    return (_tokenFlags[(int)type] & TknFLAG_TOKEN) != 0;
}
